using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
using Sentio.CodeReview.Foundation;
using System.Threading;
using System.Windows.Threading;
using System.Collections.Generic;

namespace Sentio.CodeReview.CommentsPresenter
{
    public class CommentsPresenter
    {
        IAdornmentLayer _layer;
        IWpfTextView _view;
        Brush _redBrush, _orangeBrush, _greenBrush;
        Pen _redPen, _orangePen, _greenPen;

        private Target _currentFileTarget = null;
        private bool _commentsDrawn = false;
        private readonly SolutionConfiguration _svnConfig;
        private readonly Dictionary<Point, int> _ovelappedComments = new Dictionary<Point, int>();

        public CommentsPresenter(IWpfTextView view)
        {
            _view = view;
            _layer = view.GetAdornmentLayer("Sentio.CodeReview.CommentsPresenter");

            //Listen to any event that changes the layout (text changes, scrolling, etc)
            _view.LayoutChanged += OnLayoutChanged;

            Brush penBrush = new SolidColorBrush(Colors.DarkRed);
            penBrush.Freeze();

            _redBrush = new SolidColorBrush(Color.FromArgb(50, 172, 2, 0));
            _redBrush.Freeze();
            _redPen = new Pen(penBrush, 0.5);
            _redPen.Freeze();


            _orangeBrush = new SolidColorBrush(Color.FromArgb(50, 110, 127, 128));
            _orangeBrush.Freeze();
            _orangePen = new Pen(penBrush, 0.5);
            _orangePen.Freeze();

            _greenBrush = new SolidColorBrush(Color.FromArgb(50, 0, 128, 0));
            _greenBrush.Freeze();
            _greenPen = new Pen(penBrush, 0.5);
            _greenPen.Freeze();


            _svnConfig = new SolutionConfiguration()
            {
                SvnProjectRoot = "https://svn-code-review.googlecode.com/svn/trunk/Sentio.CodeReview",
                Username = "karim.dev",
                SolutionBaseDirectory = @"C:\Users\Filip\Documents\Sentio.CodeReview\"
            };

            ThreadPool.QueueUserWorkItem(delegate
            {
                SvnTargetRepository repository = new SvnTargetRepository(_svnConfig);
                Microsoft.VisualStudio.Text.ITextDocument document = null;
                document = _view.TextDataModel.DocumentBuffer.Properties[typeof(Microsoft.VisualStudio.Text.ITextDocument)]
                            as Microsoft.VisualStudio.Text.ITextDocument;
                if (document != null || document.TextBuffer != null)
                {
                    _currentFileTarget = repository.GetTarget(document.FilePath.Replace(_svnConfig.SolutionBaseDirectory, ""));
                }
                else
                {
                    return;
                }
            });
        }

        /// <summary>
        /// On layout change add the adornment to any reformatted lines
        /// </summary>
        private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
        {
            if (!CodeReview.Editor.CodeReviewMouseProcessor.ReviewMode)
            {
                _layer.RemoveAllAdornments();
                return;
            }

            _layer.RemoveAllAdornments();
            
            foreach (BlockComment comment in _currentFileTarget.Comments)
            {
                if (comment.FromOffset > _view.TextSnapshot.Length || comment.ToOffset > _view.TextSnapshot.Length)
                {
                    continue;
                }

                SnapshotSpan span = new SnapshotSpan(_view.TextSnapshot, Span.FromBounds(comment.FromOffset, comment.ToOffset));
                Geometry g = _view.TextViewLines.GetMarkerGeometry(span);
                
                if (g != null)
                {
                    GeometryDrawing drawing = null;
                    
                    switch(comment.Status)
                    {
                        case BlockCommentStatus.Negative:
                            drawing = new GeometryDrawing(_redBrush, _redPen, g);
                            break;

                        case BlockCommentStatus.Positive:
                            drawing = new GeometryDrawing(_greenBrush, _greenPen, g);
                            break;

                        case BlockCommentStatus.Neutral:
                            drawing = new GeometryDrawing(_orangeBrush, _orangePen, g);
                            break;
                        
                        default:
                            drawing = new GeometryDrawing(_orangeBrush, _orangePen, g);
                            break;
                    }

                    drawing.Freeze();
                    
                    DrawingImage drawingImage = new DrawingImage(drawing);
                    drawingImage.Freeze();

                    Image image = new Image();
                    image.Source = drawingImage;

                    //Align the image with the top of the bounds of the text geometry
                    Canvas.SetLeft(image, g.Bounds.Left);
                    Canvas.SetTop(image, g.Bounds.Top);
                    
                    _layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, image, null);

                    if (_ovelappedComments.ContainsKey(g.Bounds.TopRight))
                    {
                        _ovelappedComments[g.Bounds.TopRight]++;
                    }
                    else
                    {
                        _ovelappedComments.Add(g.Bounds.TopRight, 0);
                    }

                    Expander details = new Expander()
                    {
                        Header = comment.Author + " on " + comment.CreatedAt + " - " + comment.Status.ToString(),
                        Margin = new Thickness(g.Bounds.TopRight.X + 10, g.Bounds.TopRight.Y - 5 + (25 * _ovelappedComments[g.Bounds.TopRight]), 0, 0),
                        HorizontalAlignment = HorizontalAlignment.Left,
                        Content = new TextBlock { Text = comment.CommentBody, Margin = new Thickness(10) },
                        Background = drawing.Brush,
                        BorderBrush = drawing.Pen.Brush
                    };
                    

                    _layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, details, null);
                }
            }
            _commentsDrawn = true;
            _ovelappedComments.Clear();
        }
    }
}
